#include <stx/test/test.hpp>

TEST_CASE (core_concepts)
{
    static_assert(std::constructible_from<double, int>);
    static_assert(std::constructible_from<int, double>);
    static_assert(std::constructible_from<short, unsigned int>);

    static_assert(IsRaw<int>);
    static_assert(!IsRaw<int const>);
    static_assert(!IsRaw<int&>);
    static_assert(!IsRaw<int const&>);
    static_assert(!IsRaw<int&&>);

    static_assert(IsCopyable<std::string>);
    static_assert(!IsCopyable<std::unique_ptr<int>>);

    static_assert(IsMovable<std::string>);
    static_assert(IsMovable<std::unique_ptr<int>>);

    static_assert(IsBoolLike<std::ofstream>);
    static_assert(IsBoolLike<int>);
    static_assert(IsBoolLike<void*>);
    static_assert(IsBoolLike<Task>);
    static_assert(IsBoolLike<int const&>);
    static_assert(IsBoolLike<int const*>);
    static_assert(IsBoolLike<std::true_type>);
    static_assert(IsBoolLike<std::false_type>);

    static_assert(IsSafeNumber<MinWidth>);
    static_assert(IsSafeBool<SbReusePort>);
    static_assert(!IsSafeNumber<int>);
    static_assert(!IsSafeBool<bool>);

    static_assert(IsAnyType<void>);
    static_assert(IsAnyType<int>);
    static_assert(IsPointer<Ptr<void>>);
    static_assert(IsPointer<Ptr<void const>>);
    static_assert(IsConst<std::remove_pointer_t<Ptr<int const>>>);
    static_assert(!IsConst<std::remove_pointer_t<Ptr<int>>>);

    CHECK(nullptr == Ptr<void>{});
    CHECK(nullptr == Ptr<int>{});
    CHECK(nullptr == Ptr<void const>{});
    CHECK(nullptr == Ptr<int const>{});

    static_assert(IsNonVoid<int>);
    static_assert(!IsNonVoid<void>);

    static_assert(std::same_as<NoCvr<int>, int>);
    static_assert(std::same_as<NoCvr<int>, int>);
    static_assert(std::same_as<NoCvr<void const>, void>);
    static_assert(std::same_as<NoCvr<int const>, int>);
    static_assert(std::same_as<NoCvr<int const&>, int>);
    static_assert(std::same_as<NoCvr<int&&>, int>);
    static_assert(std::same_as<NoCvr<int const&&>, int>);

    [](auto c) { static_assert(!AlwaysFalse<decltype(c)>); }(1);

    static_assert(IsRaw<void>);
    static_assert(IsRaw<void const*>);
    static_assert(!IsRaw<void const* const>);
    static_assert(!IsRaw<void const*&>);
    static_assert(!IsRaw<void const* const&>);
    static_assert(!IsRaw<void const*&&>);
    static_assert(!IsRaw<void const* const&&>);

    static_assert(IsCopyable<std::string>);
    static_assert(IsMovable<std::string>);

    static_assert(!IsCopyable<std::unique_ptr<int>>);
    static_assert(IsMovable<std::unique_ptr<int>>);

    static_assert(!IsCopyable<DnsCache>);
    static_assert(!IsMovable<DnsCache>);

    static_assert(IsTransferable<std::string>);
    static_assert(IsTransferable<std::string const&>);
    static_assert(IsRawTransferable<std::string>);
    static_assert(!IsRawTransferable<std::string const&>);

    static_assert(!IsBaseOf<int, int>);
    static_assert(IsBaseOf<std::string_view, StringView>);
    static_assert(IsBaseOf<std::string, std::string>);

    static_assert(IsPointer<void const*>);
    static_assert(IsPointer<void*>);
    static_assert(IsPointer<void const* const>);
    static_assert(IsPointer<void const* const&>);
    static_assert(IsPointer<void const*&&>);
    static_assert(IsPointer<void const* const&&>);

    static_assert(!IsConst<void const*>);
    static_assert(IsConst<void const* const>);
    static_assert(IsConst<void const* const&>);
    static_assert(IsConst<void const* const&&>);
    static_assert(!IsConst<void const*&>);
    static_assert(!IsConst<void const*&&>);
    static_assert(IsConst<int const>);
    static_assert(IsConst<int const&>);
    static_assert(IsConst<int const&&>);
    static_assert(!IsConst<int>);
    static_assert(!IsConst<int&>);
    static_assert(!IsConst<int&&>);

    static_assert(IsResizable<std::string>);
    static_assert(IsResizable<std::string&&>);
    static_assert(!IsResizable<std::string const>);
    static_assert(!IsResizable<std::string const&>);
    static_assert(IsResizable<std::vector<int>>);
    static_assert(IsResizable<std::vector<int>&&>);
    static_assert(!IsResizable<std::vector<int> const>);
    static_assert(!IsResizable<std::vector<int> const&>);
    static_assert(IsResizable<Buffer>);
    static_assert(IsResizable<Buffer&&>);
    static_assert(!IsResizable<Buffer const>);
    static_assert(!IsResizable<Buffer const&>);
    static_assert(!IsResizable<int[8]>);
    static_assert(!IsResizable<std::span<int>>);
    static_assert(!IsResizable<std::array<int, 8>>);
    static_assert(!IsResizable<std::initializer_list<int>>);

    static_assert(IsCallable<std::function<void(int)>, int>);

    static_assert(!IsRef<void const*>);
    static_assert(!IsRef<void const* const>);
    static_assert(IsRef<void const* const&>);
    static_assert(IsRef<void const* const&&>);
    static_assert(IsRef<void const*&>);
    static_assert(IsRef<void const*&&>);
    static_assert(!IsRef<int const>);
    static_assert(IsRef<int const&>);
    static_assert(IsRef<int const&&>);
    static_assert(!IsRef<int>);
    static_assert(IsRef<int&>);
    static_assert(IsRef<int&&>);

    static_assert(IsLvRef<void const*&>);
    static_assert(IsLvRef<void const* const&>);
    static_assert(IsClvRef<void const* const&>);
    static_assert(!IsClvRef<void const*&>);
    static_assert(!IsLvRef<void const* const>);
    static_assert(!IsLvRef<void const* const&&>);
    static_assert(!IsLvRef<void const*&&>);
    static_assert(!IsClvRef<void const* const&&>);
    static_assert(!IsClvRef<void const*&&>);

    static_assert(IsRvRef<void const*&&>);
    static_assert(IsRvRef<void const* const&&>);
    static_assert(IsCrvRef<void const* const&&>);
    static_assert(!IsCrvRef<void const*&&>);
    static_assert(!IsRvRef<void const* const>);
    static_assert(!IsRvRef<void const* const&>);
    static_assert(!IsRvRef<void const*&>);
    static_assert(!IsCrvRef<void const* const&>);
    static_assert(!IsCrvRef<void const*&>);

    static_assert(IsRef<void const* const&>);
    static_assert(IsRef<void const* const&&>);
    static_assert(IsRef<void const*&>);
    static_assert(IsRef<void const*&&>);
    static_assert(!IsRef<int const>);
    static_assert(IsRef<int const&>);
    static_assert(IsRef<int const&&>);
    static_assert(!IsRef<int>);
    static_assert(IsRef<int&>);
    static_assert(IsRef<int&&>);

    static_assert(IsOctet<char>);
    static_assert(IsOctet<signed char>);
    static_assert(IsOctet<unsigned char>);
    static_assert(IsOctet<std::byte>);
    static_assert(IsOctet<char8_t>);

    static_assert(IsOctet<char const&>);
    static_assert(IsOctet<signed char const&>);
    static_assert(IsOctet<unsigned char const&>);
    static_assert(IsOctet<std::byte const&>);
    static_assert(IsOctet<char8_t const&>);

    static_assert(IsRawOctet<char>);
    static_assert(IsRawOctet<signed char>);
    static_assert(IsRawOctet<unsigned char>);
    static_assert(IsRawOctet<std::byte>);
    static_assert(IsRawOctet<char8_t>);
    static_assert(!IsRawOctet<char const&>);

    static_assert(IsPod<char>);
    static_assert(IsPod<long long>);
    static_assert(IsPod<char const&>);
    static_assert(IsPod<long long const&>);
    static_assert(IsPod<::sockaddr>);
    static_assert(IsPod<::sockaddr&>);

    static_assert(IsMemArea<std::string>);
    static_assert(IsMemArea<std::string_view>);
    static_assert(IsMemArea<Buffer>);
    static_assert(IsMemArea<std::vector<::sockaddr>>);
    static_assert(IsMemArea<std::span<::sockaddr>>);
    static_assert(IsMemArea<std::array<::sockaddr, 8>>);
    static_assert(IsMemArea<std::initializer_list<::sockaddr>>);

    static_assert(IsPen<void*>);
    static_assert(IsPen<Tco>);
    static_assert(IsPen<int>);

    static_assert(IsSizedRange<std::string>);
    static_assert(IsSizedRange<int[8]>);
    static_assert(!IsSizedRange<int>);

    static_assert(IsIntegral<int&>);
    static_assert(IsIntegral<int const&>);
    static_assert(IsIntegral<int&&>);
    static_assert(IsIntegral<int const&&>);
    static_assert(IsIntegral<bool>);
    static_assert(IsIntegral<signed char>);
    static_assert(IsIntegral<unsigned char>);
    static_assert(IsIntegral<signed short>);
    static_assert(IsIntegral<unsigned short>);
    static_assert(IsIntegral<signed int>);
    static_assert(IsIntegral<unsigned int>);
    static_assert(IsIntegral<signed long>);
    static_assert(IsIntegral<unsigned long>);
    static_assert(IsIntegral<signed long long>);
    static_assert(IsIntegral<unsigned long long>);
    static_assert(!IsIntegral<float>);
    static_assert(!IsIntegral<double>);
    static_assert(!IsIntegral<void>);

    static_assert(IsIntegralLike<int&>);
    static_assert(IsIntegralLike<Tco>);

    static_assert(IsRawIntegral<int>);
    static_assert(!IsRawIntegral<int&>);
    static_assert(!IsRawIntegral<int const&>);
    static_assert(!IsRawIntegral<int&&>);
    static_assert(!IsRawIntegral<int const&&>);

    static_assert(!IsFloatingPoint<bool>);
    static_assert(!IsFloatingPoint<signed char>);
    static_assert(!IsFloatingPoint<unsigned char>);
    static_assert(!IsFloatingPoint<signed short>);
    static_assert(!IsFloatingPoint<unsigned short>);
    static_assert(!IsFloatingPoint<signed int>);
    static_assert(!IsFloatingPoint<unsigned int>);
    static_assert(!IsFloatingPoint<signed long>);
    static_assert(!IsFloatingPoint<unsigned long>);
    static_assert(!IsFloatingPoint<signed long long>);
    static_assert(!IsFloatingPoint<unsigned long long>);
    static_assert(IsFloatingPoint<float>);
    static_assert(IsFloatingPoint<double>);
    static_assert(!IsFloatingPoint<void>);

    static_assert(IsRawFloatingPoint<float>);
    static_assert(IsRawFloatingPoint<double>);
    static_assert(!IsRawFloatingPoint<float&>);
    static_assert(!IsRawFloatingPoint<float const&>);
    static_assert(!IsRawFloatingPoint<float&&>);
    static_assert(!IsRawFloatingPoint<float const&&>);
    static_assert(!IsRawFloatingPoint<double&>);
    static_assert(!IsRawFloatingPoint<double const&>);
    static_assert(!IsRawFloatingPoint<double&&>);
    static_assert(!IsRawFloatingPoint<double const&&>);

    static_assert(IsArithmetic<int const&>);
    static_assert(IsArithmetic<bool>);
    static_assert(IsArithmetic<signed char>);
    static_assert(IsArithmetic<unsigned char>);
    static_assert(IsArithmetic<signed short>);
    static_assert(IsArithmetic<unsigned short>);
    static_assert(IsArithmetic<signed int>);
    static_assert(IsArithmetic<unsigned int>);
    static_assert(IsArithmetic<signed long>);
    static_assert(IsArithmetic<unsigned long>);
    static_assert(IsArithmetic<signed long long>);
    static_assert(IsArithmetic<unsigned long long>);
    static_assert(IsArithmetic<float>);
    static_assert(IsArithmetic<double>);
    static_assert(!IsArithmetic<void>);

    static_assert(!IsRawArithmetic<int const&>);
    static_assert(IsRawArithmetic<int>);

    static_assert(IsEnum<Tco>);
    static_assert(IsEnum<Tco const&>);
    static_assert(!IsEnum<int>);
    static_assert(IsRawEnum<Tco>);
    static_assert(!IsRawEnum<Tco const&>);
    static_assert(!IsRawEnum<int>);

    static_assert(IsRange<std::string>);
    static_assert(IsRange<std::string&>);
    static_assert(IsRange<std::string const&>);
    static_assert(IsRange<std::string&&>);
    static_assert(IsRange<std::string const&&>);

    {
        auto is = std::istringstream("");
        static_assert(IsInputRange<decltype(ranges::subrange(
                          std::istream_iterator<int>(is),
                          std::istream_iterator<int>{}))>);
        static_assert(!IsForwardRange<decltype(ranges::subrange(
                          std::istream_iterator<int>(is),
                          std::istream_iterator<int>{}))>);
    }

    static_assert(IsForwardRange<std::forward_list<int>>);
    static_assert(!IsBidirectionalRange<std::forward_list<int>>);

    static_assert(IsBidirectionalRange<std::list<int>>);
    static_assert(!IsRandomAccessRange<std::list<int>>);

    static_assert(IsRandomAccessRange<std::deque<int>>);
    static_assert(!IsContiguousRange<std::deque<int>>);

    static_assert(IsSizedRange<std::list<int>>);
    static_assert(!IsSizedRange<std::forward_list<int>>);

    static_assert(!IsViewableRange<std::list<int>>);
    static_assert(!IsViewableRange<std::forward_list<int>>);
    static_assert(!IsViewableRange<int[8]>);
    static_assert(!IsViewableRange<std::initializer_list<int>>);
    static_assert(!IsViewableRange<std::array<int, 8>>);
    static_assert(IsViewableRange<std::list<int>&>);
    static_assert(IsViewableRange<std::forward_list<int>&>);
    static_assert(IsViewableRange<std::string_view>);
    static_assert(IsViewableRange<std::span<int>>);
    static_assert(IsViewableRange<StringView>);
    static_assert(IsViewableRange<JoinSeparator>);
    static_assert(IsViewableRange<Prefix>);
    static_assert(IsViewableRange<Postfix>);
    static_assert(IsViewableRange<StringLiteral<8>>);

    {
        auto const coll = std::list<int>{};
        static_assert(IsViewableRange<decltype(views::all(coll))>);
    }

    static_assert(!IsBorrowedRange<std::list<int>>);
    static_assert(!IsBorrowedRange<std::forward_list<int>>);
    static_assert(!IsBorrowedRange<int[8]>);
    static_assert(!IsBorrowedRange<std::initializer_list<int>>);
    static_assert(!IsBorrowedRange<std::array<int, 8>>);
    static_assert(IsBorrowedRange<std::list<int>&>);
    static_assert(IsBorrowedRange<std::forward_list<int>&>);
    static_assert(IsBorrowedRange<std::string_view>);
    static_assert(IsBorrowedRange<std::span<int>>);
    static_assert(IsBorrowedRange<StringView>);
    static_assert(IsBorrowedRange<JoinSeparator>);
    static_assert(IsBorrowedRange<Prefix>);
    static_assert(IsBorrowedRange<Postfix>);
    static_assert(IsBorrowedRange<StringLiteral<8>>);

    {
        auto const coll = std::list<int>{};
        static_assert(IsBorrowedRange<decltype(views::all(coll))>);
    }

    static_assert(IsContiguousRange<int[8]>);
    static_assert(IsContiguousRange<std::initializer_list<int>>);
    static_assert(IsContiguousRange<std::array<int, 8>>);
    static_assert(IsContiguousRange<std::span<int>>);
    static_assert(IsContiguousRange<std::vector<int>>);
    static_assert(IsContiguousRange<std::string>);
    static_assert(IsContiguousRange<std::string_view>);
    static_assert(IsContiguousRange<StringView>);
    static_assert(IsContiguousRange<JoinSeparator>);
    static_assert(IsContiguousRange<Prefix>);
    static_assert(IsContiguousRange<Postfix>);
    static_assert(IsContiguousRange<StringLiteral<8>>);

    {
        struct MySimplestView final : public std::ranges::view_base
        {
            char* begin() const noexcept
            {
                return {};
            }

            char* end() const noexcept
            {
                return {};
            }
        };

        static_assert(!IsBorrowedRange<MySimplestView>);
    }

    static_assert(std::same_as<RangeValueType<std::string>, char>);
    static_assert(std::same_as<RangeValueType<std::string&>, char>);
    static_assert(std::same_as<RangeValueType<std::string const&>, char>);
    static_assert(std::same_as<RangeValueType<std::string&&>, char>);
    static_assert(std::same_as<RangeValueType<std::string const&&>, char>);

    static_assert(IsIdentical<int, int>);
    static_assert(IsIdentical<int&, int>);
    static_assert(IsIdentical<int const, int const volatile>);
    static_assert(IsIdentical<int const&, int>);
    static_assert(IsIdentical<int&&, int>);
    static_assert(IsIdentical<int const&&, int>);
    static_assert(IsIdentical<int, int&&>);

    {
        struct A
        {
            char a;
        };

        enum class B : char
        {
            a,
            b,
            c
        };

        struct C
        {
            int c;
        };

        struct D : A
        {
            bool f()
            {
                return a > 0;
            }
        };

        struct E : A
        {
            int e;
        };

        static_assert(IsPod<char>);
        static_assert(IsPod<signed char>);
        static_assert(IsPod<unsigned char>);
        static_assert(IsPod<char8_t>);
        static_assert(IsPod<std::byte>);
        static_assert(IsPod<A>);
        static_assert(IsPod<B>);
        static_assert(IsPod<C>);
        static_assert(IsPod<D>);
        static_assert(!IsPod<E>);

        static_assert(IsRawPod<char>);
        static_assert(IsRawPod<signed char>);
        static_assert(IsRawPod<unsigned char>);
        static_assert(IsRawPod<char8_t>);
        static_assert(IsRawPod<std::byte>);
        static_assert(IsRawPod<A>);
        static_assert(IsRawPod<B>);
        static_assert(IsRawPod<C>);
        static_assert(IsRawPod<D>);
        static_assert(!IsRawPod<E>);

        static_assert(IsOctet<char>);
        static_assert(IsOctet<signed char>);
        static_assert(IsOctet<unsigned char>);
        static_assert(IsOctet<char8_t>);
        static_assert(IsOctet<std::byte>);
        static_assert(IsOctet<A>);
        static_assert(IsOctet<B>);
        static_assert(!IsOctet<C>);
        static_assert(IsOctet<D>);
        static_assert(!IsOctet<E>);

        static_assert(IsRawOctet<char>);
        static_assert(IsRawOctet<signed char>);
        static_assert(IsRawOctet<unsigned char>);
        static_assert(IsRawOctet<char8_t>);
        static_assert(IsRawOctet<std::byte>);
        static_assert(IsRawOctet<A>);
        static_assert(IsRawOctet<B>);
        static_assert(!IsRawOctet<C>);
        static_assert(IsRawOctet<D>);
        static_assert(!IsRawOctet<E>);
    }

    static_assert(IsAnsiChar<char>);
    static_assert(!IsAnsiChar<wchar_t>);
    static_assert(!IsAnsiChar<char8_t>);
    static_assert(!IsAnsiChar<char16_t>);
    static_assert(!IsAnsiChar<char32_t>);

    static_assert(IsStdChar<char>);
    static_assert(IsStdChar<wchar_t>);
    static_assert(IsStdChar<char const&>);
    static_assert(!IsStdChar<char8_t>);
    static_assert(!IsStdChar<char16_t>);
    static_assert(!IsStdChar<char32_t>);
    static_assert(!IsStdChar<signed char>);
    static_assert(!IsStdChar<unsigned char>);
    static_assert(!IsStdChar<int>);

    static_assert(IsExStdChar<char>);
    static_assert(IsExStdChar<wchar_t>);
    static_assert(IsExStdChar<char const&>);
    static_assert(IsExStdChar<char8_t>);
    static_assert(IsExStdChar<char16_t>);
    static_assert(IsExStdChar<char32_t>);
    static_assert(!IsExStdChar<signed char>);
    static_assert(!IsExStdChar<unsigned char>);
    static_assert(!IsExStdChar<int>);

    static_assert(IsRawStdChar<char>);
    static_assert(!IsRawStdChar<char const&>);
    static_assert(IsRawExStdChar<char8_t>);
    static_assert(!IsRawExStdChar<char8_t const&>);

    static_assert(!IsConstructibleFromExStdStringView<int>);
    static_assert(IsConstructibleFromExStdStringView<char[8]>);
    static_assert(IsConstructibleFromExStdStringView<char*>);
    static_assert(IsConstructibleFromExStdStringView<char const[8]>);
    static_assert(IsConstructibleFromExStdStringView<char const* const>);
    static_assert(IsConstructibleFromExStdStringView<std::string>);
    static_assert(IsConstructibleFromExStdStringView<std::string_view>);
    static_assert(IsConstructibleFromExStdStringView<StringView>);

    static_assert(!IsMemArea<std::list<char>>);
    static_assert(!IsMemArea<std::deque<char>>);
    static_assert(IsMemArea<int[8]>);
    static_assert(IsMemArea<std::initializer_list<int>>);
    static_assert(IsMemArea<std::array<int, 8>>);
    static_assert(IsMemArea<std::span<int>>);
    static_assert(IsMemArea<std::vector<int>>);
    static_assert(IsMemArea<std::string>);
    static_assert(IsMemArea<std::string_view>);
    static_assert(IsMemArea<StringView>);
    static_assert(IsMemArea<JoinSeparator>);
    static_assert(IsMemArea<Prefix>);
    static_assert(IsMemArea<Postfix>);
    static_assert(IsMemArea<StringLiteral<8>>);

    static_assert(!IsStringLike<std::list<char>>);
    static_assert(!IsStringLike<std::deque<char>>);
    static_assert(IsStringLike<char*>);
    static_assert(IsStringLike<char[8]>);
    static_assert(IsStringLike<char[]>);
    static_assert(IsStringLike<std::initializer_list<char>>);
    static_assert(IsStringLike<std::array<char, 8>>);
    static_assert(IsStringLike<std::span<char>>);
    static_assert(IsStringLike<std::vector<char>>);
    static_assert(IsStringLike<std::string>);
    static_assert(IsStringLike<std::string_view>);
    static_assert(IsStringLike<StringView>);
    static_assert(IsStringLike<JoinSeparator>);
    static_assert(IsStringLike<Prefix>);
    static_assert(IsStringLike<Postfix>);
    static_assert(IsStringLike<StringLiteral<8>>);

    static_assert(IsStdZstring<char[8]>);
    static_assert(IsStdZstring<char*>);
    static_assert(IsStdZstring<char const*>);
    static_assert(IsStdZstring<char const* const>);
    static_assert(IsStdZstring<std::string>);
    static_assert(IsStdZstring<StringView>);
    static_assert(IsStdZstring<StringLiteral<8>>);
    static_assert(IsStdZstring<WideStringLiteral<8>>);
    static_assert(!IsStdZstring<U8StringLiteral<8>>);
    static_assert(!IsStdZstring<U16StringLiteral<8>>);
    static_assert(!IsStdZstring<U32StringLiteral<8>>);
    static_assert(!IsStdZstring<std::string_view>);
    static_assert(!IsStdZstring<std::wstring_view>);
    static_assert(!IsStdZstring<std::u8string_view>);
    static_assert(!IsStdZstring<std::u16string_view>);
    static_assert(!IsStdZstring<std::u32string_view>);
    static_assert(IsStdZstring<WideStringView>);
    static_assert(!IsStdZstring<U8StringView>);
    static_assert(!IsStdZstring<U16StringView>);
    static_assert(!IsStdZstring<U32StringView>);
    static_assert(IsStdZstring<std::wstring>);
    static_assert(!IsStdZstring<std::u8string>);
    static_assert(!IsStdZstring<std::u16string>);
    static_assert(!IsStdZstring<std::u32string>);
    static_assert(IsExStdZstring<std::u8string>);
    static_assert(IsExStdZstring<std::u16string>);
    static_assert(IsExStdZstring<std::u32string>);
    static_assert(IsStdZstring<wchar_t[8]>);
    static_assert(!IsStdZstring<char8_t[8]>);
    static_assert(IsStdCharStringLike<char[8]>);
    static_assert(IsStdCharStringLike<wchar_t[8]>);
    static_assert(!IsStdCharStringLike<char8_t[8]>);

    static_assert(std::same_as<StringCharType<char[8]>, char>);
    static_assert(std::same_as<StringCharType<char const* const>, char>);
    static_assert(std::same_as<StringCharType<std::string const&>, char>);
    static_assert(std::same_as<StringCharType<std::string>, char>);
    static_assert(std::same_as<StringCharType<std::wstring>, wchar_t>);
    static_assert(std::same_as<StringCharType<std::u8string>, char8_t>);
    static_assert(std::same_as<StringCharType<std::u16string>, char16_t>);
    static_assert(std::same_as<StringCharType<std::u32string>, char32_t>);
    static_assert(std::same_as<StringCharType<StringLiteral<8>>, char>);
    static_assert(std::same_as<StringCharType<StringView>, char>);

    static_assert(IsStdTuple<std::tuple<int, double, std::string>>);
    static_assert(IsStdTuple<std::pair<int, double>>);
    static_assert(!IsStdTuple<std::string>);

    static_assert(IsStdInitializerList<std::initializer_list<int>>);
    static_assert(!IsStdInitializerList<std::string>);

    static_assert(IsStdArray<std::array<int, 8>>);
    static_assert(!IsStdArray<std::string>);

    static_assert(IsStdSpan<std::span<int>>);
    static_assert(!IsStdSpan<std::string>);

    static_assert(IsStdStack<std::stack<int>>);
    static_assert(!IsStdStack<std::string>);

    static_assert(IsStdQueue<std::queue<int>>);
    static_assert(!IsStdQueue<std::string>);

    static_assert(IsStdPriorityQueue<std::priority_queue<int>>);
    static_assert(!IsStdPriorityQueue<std::string>);

    static_assert(IsStdStringView<std::string_view>);
    static_assert(!IsStdStringView<std::u8string_view>);
    static_assert(!IsStdStringView<std::string>);

    static_assert(IsExStdStringView<std::string_view>);
    static_assert(IsExStdStringView<std::u8string_view>);
    static_assert(!IsExStdStringView<std::string>);

    static_assert(IsStdString<std::string>);
    static_assert(!IsStdString<std::u8string>);
    static_assert(!IsStdString<Buffer>);

    static_assert(IsExStdString<std::string>);
    static_assert(IsExStdString<std::u8string>);
    static_assert(!IsExStdString<Buffer>);

    static_assert(IsStdVector<std::vector<int>>);
    static_assert(IsStdVector<Buffer>);

    static_assert(IsStdDeque<std::deque<int>>);
    static_assert(!IsStdDeque<Buffer>);

    static_assert(IsStdForwardList<std::forward_list<int>>);
    static_assert(!IsStdForwardList<Buffer>);

    static_assert(IsStdList<std::list<int>>);
    static_assert(!IsStdList<Buffer>);

    static_assert(IsStdSet<std::set<int>>);
    static_assert(!IsStdSet<Buffer>);

    static_assert(IsStdMultiset<std::multiset<int>>);
    static_assert(!IsStdMultiset<Buffer>);

    static_assert(IsStdMap<std::map<int, double>>);
    static_assert(!IsStdMap<Buffer>);

    static_assert(IsStdMultimap<std::multimap<int, double>>);
    static_assert(!IsStdMultimap<Buffer>);

    static_assert(IsStdUnorderedSet<std::unordered_set<int>>);
    static_assert(!IsStdUnorderedSet<Buffer>);

    static_assert(IsStdUnorderedMultiset<std::unordered_multiset<int>>);
    static_assert(!IsStdUnorderedMultiset<Buffer>);

    static_assert(IsStdUnorderedMap<std::unordered_map<int, double>>);
    static_assert(!IsStdUnorderedMap<Buffer>);

    static_assert(IsStdUnorderedMultimap<std::unordered_multimap<int, double>>);
    static_assert(!IsStdUnorderedMultimap<Buffer>);

    static_assert(IsStdInsertableContainer<std::stack<int>>);
    static_assert(IsStdInsertableContainer<std::queue<int>>);
    static_assert(IsStdInsertableContainer<std::priority_queue<int>>);
    static_assert(IsStdInsertableContainer<std::string>);
    static_assert(IsStdInsertableContainer<std::vector<int>>);
    static_assert(IsStdInsertableContainer<std::deque<int>>);
    static_assert(IsStdInsertableContainer<std::list<int>>);
    static_assert(IsStdInsertableContainer<std::forward_list<int>>);
    static_assert(IsStdInsertableContainer<std::set<int>>);
    static_assert(IsStdInsertableContainer<std::map<int, double>>);
    static_assert(IsStdInsertableContainer<std::multiset<int>>);
    static_assert(IsStdInsertableContainer<std::multimap<int, double>>);
    static_assert(IsStdInsertableContainer<std::unordered_set<int>>);
    static_assert(IsStdInsertableContainer<std::unordered_map<int, double>>);
    static_assert(IsStdInsertableContainer<std::unordered_multiset<int>>);
    static_assert(IsStdInsertableContainer<std::unordered_map<int, double>>);

    static_assert(!IsStdAssociativeContainer<std::stack<int>>);
    static_assert(!IsStdAssociativeContainer<std::queue<int>>);
    static_assert(!IsStdAssociativeContainer<std::priority_queue<int>>);
    static_assert(!IsStdAssociativeContainer<std::string>);
    static_assert(!IsStdAssociativeContainer<std::vector<int>>);
    static_assert(!IsStdAssociativeContainer<std::deque<int>>);
    static_assert(!IsStdAssociativeContainer<std::list<int>>);
    static_assert(!IsStdAssociativeContainer<std::forward_list<int>>);
    static_assert(IsStdAssociativeContainer<std::set<int>>);
    static_assert(IsStdAssociativeContainer<std::map<int, double>>);
    static_assert(IsStdAssociativeContainer<std::multiset<int>>);
    static_assert(IsStdAssociativeContainer<std::multimap<int, double>>);
    static_assert(IsStdAssociativeContainer<std::unordered_set<int>>);
    static_assert(IsStdAssociativeContainer<std::unordered_map<int, double>>);
    static_assert(IsStdAssociativeContainer<std::unordered_multiset<int>>);
    static_assert(IsStdAssociativeContainer<std::unordered_map<int, double>>);

    static_assert(IsStdInsertableSequenceContainer<std::stack<int>>);
    static_assert(IsStdInsertableSequenceContainer<std::queue<int>>);
    static_assert(IsStdInsertableSequenceContainer<std::priority_queue<int>>);
    static_assert(IsStdInsertableSequenceContainer<std::string>);
    static_assert(IsStdInsertableSequenceContainer<std::vector<int>>);
    static_assert(IsStdInsertableSequenceContainer<std::deque<int>>);
    static_assert(IsStdInsertableSequenceContainer<std::list<int>>);
    static_assert(IsStdInsertableSequenceContainer<std::forward_list<int>>);
    static_assert(!IsStdInsertableSequenceContainer<std::set<int>>);
    static_assert(!IsStdInsertableSequenceContainer<std::map<int, double>>);
    static_assert(!IsStdInsertableSequenceContainer<std::multiset<int>>);
    static_assert(
        !IsStdInsertableSequenceContainer<std::multimap<int, double>>);
    static_assert(!IsStdInsertableSequenceContainer<std::unordered_set<int>>);
    static_assert(
        !IsStdInsertableSequenceContainer<std::unordered_map<int, double>>);
    static_assert(
        !IsStdInsertableSequenceContainer<std::unordered_multiset<int>>);
    static_assert(
        !IsStdInsertableSequenceContainer<std::unordered_map<int, double>>);

    CHECK("[1, 2, 3]"sv ==
          scat("["_prefix, ", "_I, "]"_postfix, "1"sv, "2"sv, "3"sv));

    static_assert(IsAbsTimePoint<decltype(SystemClock::now())>);
    static_assert(IsAbsTimePoint<decltype(FileClock::now())>);
    static_assert(IsRelTimePoint<decltype(SteadyClock::now())>);
    static_assert(IsStdTimePoint<decltype(SystemClock::now())>);
    static_assert(IsStdTimePoint<decltype(FileClock::now())>);
    static_assert(IsStdTimePoint<decltype(SteadyClock::now())>);
    static_assert(IsStdDuration<decltype(5s)>);

    static_assert(IsStdRegex<std::regex>);
    static_assert(IsStdRegex<std::wregex>);

    static_assert(IsExStdZstring<char[8]>);
    static_assert(IsExStdZstring<char[]>);
    static_assert(IsExStdZstring<wchar_t[8]>);
    static_assert(IsExStdZstring<wchar_t[]>);
    static_assert(IsExStdZstring<char8_t[8]>);
    static_assert(IsExStdZstring<char8_t[]>);
    static_assert(IsExStdZstring<char16_t[8]>);
    static_assert(IsExStdZstring<char16_t[]>);
    static_assert(IsExStdZstring<char32_t[8]>);
    static_assert(IsExStdZstring<char32_t[]>);

    static_assert(IsExStdZstring<char*>);
    static_assert(IsExStdZstring<char const*>);
    static_assert(IsExStdZstring<char* const>);
    static_assert(IsExStdZstring<char const* const>);
    static_assert(IsExStdZstring<wchar_t*>);
    static_assert(IsExStdZstring<wchar_t const*>);
    static_assert(IsExStdZstring<wchar_t* const>);
    static_assert(IsExStdZstring<wchar_t const* const>);
    static_assert(IsExStdZstring<char8_t*>);
    static_assert(IsExStdZstring<char8_t const*>);
    static_assert(IsExStdZstring<char8_t* const>);
    static_assert(IsExStdZstring<char8_t const* const>);
    static_assert(IsExStdZstring<char16_t*>);
    static_assert(IsExStdZstring<char16_t const*>);
    static_assert(IsExStdZstring<char16_t* const>);
    static_assert(IsExStdZstring<char16_t const* const>);
    static_assert(IsExStdZstring<char32_t*>);
    static_assert(IsExStdZstring<char32_t const*>);
    static_assert(IsExStdZstring<char32_t* const>);
    static_assert(IsExStdZstring<char32_t const* const>);

    static_assert(IsExStdZstring<decltype("hello"_sv)>);
    static_assert(IsExStdZstring<decltype(L"hello"_sv)>);
    static_assert(IsExStdZstring<decltype(u8"hello"_sv)>);
    static_assert(IsExStdZstring<decltype(u"hello"_sv)>);
    static_assert(IsExStdZstring<decltype(U"hello"_sv)>);

    static_assert(IsExStdZstring<BasicStringLiteral<char, 8>>);
    static_assert(IsExStdZstring<BasicStringLiteral<wchar_t, 8>>);
    static_assert(IsExStdZstring<BasicStringLiteral<char8_t, 8>>);
    static_assert(IsExStdZstring<BasicStringLiteral<char16_t, 8>>);
    static_assert(IsExStdZstring<BasicStringLiteral<char32_t, 8>>);

    static_assert(IsExStdZstring<decltype("hello"s)>);
    static_assert(IsExStdZstring<decltype(L"hello"s)>);
    static_assert(IsExStdZstring<decltype(u8"hello"s)>);
    static_assert(IsExStdZstring<decltype(u"hello"s)>);
    static_assert(IsExStdZstring<decltype(U"hello"s)>);

    static_assert(!IsExStdZstring<decltype("hello"sv)>);
    static_assert(!IsExStdZstring<decltype(L"hello"sv)>);
    static_assert(!IsExStdZstring<decltype(u8"hello"sv)>);
    static_assert(!IsExStdZstring<decltype(u"hello"sv)>);
    static_assert(!IsExStdZstring<decltype(U"hello"sv)>);
}